﻿
Imports std

Namespace internalFunctions
    'parameters, i1, input int/float
    '            i2, input int/float
    'output, int/float, invokeImpl(i1,i2)
    Public MustInherit Class twonumberoper
        Inherits internalFunction

        Public Class parameters
            Public Const i1 As String = "i1"
            Public Const i2 As String = "i2"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.i1, parameters.i2)
        End Sub

        Protected Sub New(ByVal name As String)
            Me.New(name, Nothing)
        End Sub

        Protected Sub New(ByVal name As String, ByVal aliases As aliases)
            MyBase.New(name, m, aliases)
        End Sub

        Protected MustOverride Overloads Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double

        Protected NotOverridable Overrides Function invoke(ByVal ctx As context, _
                                                           ByRef output As bare_variable) As Boolean
            Dim i1 As Double
            If ctx.findVariableFloat(parameters.i1, i1) Then
                Dim i2 As Double
                If ctx.findVariableFloat(parameters.i2, i2) Then
                    Dim rst As Double
                    Try
                        rst = invokeImpl(i1, i2)
                    Catch ex As Exception
                        raiseError("cannot invokeImpl(i1,i2), i1=" + Convert.ToString(i1) + _
                                   ", i2=" + Convert.ToString(i2) + ", ex " + ex.Message, errorHandle.errorType.user)
                        Return False
                    End Try
                    Dim rsti As Int64
                    If convertor.toint64(rst, rsti) Then
                        output = New bare_variable(typeDefination.int, rsti)
                    Else
                        output = New bare_variable(typeDefination.float, rst)
                    End If

                    Return True
                Else
                    raiseError("expect parameter " + parameters.i2, errorHandle.errorType.user)
                    Return False
                End If
            Else
                raiseError("expect parameter " + parameters.i1, errorHandle.errorType.user)
                Return False
            End If
        End Function
    End Class

    'parameters, i1, input int/float
    '            i2, input int/float
    '            ...
    '            in, input int/float
    'output, int/float, invokeImpl(i1,i2,...,in)
    Public MustInherit Class multiplenumberoper
        Inherits internalFunction

        Public Class parameters
            Public Const ibase As String = "i"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialSerialMapping(m, parameters.ibase)
        End Sub

        Protected Sub New(ByVal name As String)
            MyBase.New(name, m)
        End Sub

        Protected Sub New(ByVal name As String, ByVal aliases As aliases)
            MyBase.New(name, m, aliases)
        End Sub

        Protected MustOverride Overloads Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double
        Protected MustOverride Overloads Function invokeImpl(ByVal i1 As Int64, ByVal i2 As Int64) As Int64
        Protected MustOverride Function initialValue() As Double

        Private Function callback(ByVal name As String, ByVal v As Double, ByRef obj As Object) As Boolean
            obj = invokeImpl(convertor.cast(Of Double)(obj), v)
            Return True
        End Function

        Private Function callback(ByVal name As String, ByVal v As Int64, ByRef obj As Object) As Boolean
            obj = invokeImpl(convertor.cast(Of Int64)(obj), v)
            Return True
        End Function

        Protected NotOverridable Overrides Function invoke(ByVal ctx As context, _
                                                           ByRef output As bare_variable) As Boolean
            Dim rtn As Double
            rtn = initialValue()
            Dim rtni As Int64
            rtni = initialValue()

            If ctx.findVariables(AddressOf callback, int_finder(), parameters.ibase, 0, rtni) OrElse _
               ctx.findVariables(AddressOf callback, int_finder(), parameters.ibase, 1, rtni) Then
                output = New bare_variable(typeDefination.int, rtni)
            Else
                If ctx.findVariables(AddressOf callback, float_finder(), parameters.ibase, 0, rtn) OrElse _
                   ctx.findVariables(AddressOf callback, float_finder(), parameters.ibase, 1, rtn) Then
                    output = New bare_variable(typeDefination.float, rtn)
                End If
            End If

            Return True
        End Function
    End Class

    'parameters, same as multiplenumberoper
    'output, i1+i2+...+in
    Public Class increase
        Inherits multiplenumberoper

        Private Shared _aliases As aliases = Nothing

        Shared Sub New()
            initialAliases(_aliases, "+")
        End Sub

        Public Sub New()
            MyBase.New("increase", _aliases)
        End Sub

        Protected Overrides Function initialValue() As Double
            Return 0
        End Function

        Protected Overrides Function invokeImpl(ByVal i1 As Int64, ByVal i2 As Int64) As Int64
            Return i1 + i2
        End Function

        Protected Overrides Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double
            Return i1 + i2
        End Function
    End Class

    'parameters, i, input int/float
    'output, int/float, -i
    Public Class negative
        Inherits internalFunction

        Public Class parameters
            Public Const i As String = "i"
        End Class

        Private Shared _aliases As aliases = Nothing
        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialAliases(_aliases, "-")
            initialMapping(m, parameters.i)
        End Sub

        Public Sub New()
            MyBase.New("negative", m, _aliases)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim i As Int64
            If ctx.findVariableInt(parameters.i, i) Then
                output = New bare_variable(typeDefination.int, -i)
                Return True
            End If
            Dim d As Double
            If ctx.findVariableFloat(parameters.i, d) Then
                output = New bare_variable(typeDefination.float, -d)
                Return True
            End If

            raiseError("expect parameter " + parameters.i, errorHandle.errorType.user)
            Return False
        End Function
    End Class

    'parameters, same as twonumberoper
    'output, i1/i2
    Public Class divide
        Inherits twonumberoper

        Private Shared _aliases As aliases = Nothing

        Shared Sub New()
            initialAliases(_aliases, "/")
        End Sub

        Public Sub New()
            MyBase.New("div", _aliases)
        End Sub

        Protected Overrides Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double
            Return i1 / i2
        End Function
    End Class

    Public Class divideexactly
        Inherits twonumberoper

        Private Shared a As aliases = Nothing

        Shared Sub New()
            initialAliases(a, "\")
        End Sub

        Public Sub New()
            MyBase.New("dive", a)
        End Sub

        Protected Overrides Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double
            Return i1 \ i2
        End Function
    End Class

    'parameters, same as multinumberoper
    'output, i1*i2*...*in
    Public Class multiply
        Inherits multiplenumberoper

        Private Shared _aliases As aliases = Nothing

        Shared Sub New()
            initialAliases(_aliases, "*")
        End Sub

        Public Sub New()
            MyBase.New("multiply", _aliases)
        End Sub

        Protected Overrides Function initialValue() As Double
            Return 1
        End Function

        Protected Overrides Function invokeImpl(ByVal i1 As Int64, ByVal i2 As Int64) As Int64
            Return i1 * i2
        End Function

        Protected Overrides Function invokeImpl(ByVal i1 As Double, ByVal i2 As Double) As Double
            Return i1 * i2
        End Function
    End Class
End Namespace